package appTool

import (
	"gitee.com/kinwyb/appTools/common"
	"gitee.com/kinwyb/conv"
	"github.com/sirupsen/logrus"
	"os"
	"regexp"
	"strings"
)

type RunMode string

const (
	DevTrace RunMode = "dev_trace"
	DEV      RunMode = "dev"
	PRO      RunMode = "pro"
)

func (r RunMode) String() string {
	if r == DevTrace { //dev_trace 输出就是dev
		return "dev"
	}
	return string(r)
}

const (
	systemConfigRunMode        = "runMode"        //运行模式
	systemConfigEtcdHost       = "etcd.host"      //etcd地址
	systemConfigTraceServerURL = "trace.url"      //追踪服务地址
	systemConfigZipkinURL      = "zipkin.url"     //zipkin地址
	systemConfigLogToFile      = "logToFile"      //日志写入文件
	pprofPortConfigKey         = "pprof.port"     //调试端口
	broadcastKey               = "broadcast.path" //广播
)

// ConfigReader 配置读取结构
type ConfigReader interface {
	// ReadString 读取一个string类型配置值
	ReadString(key string, defaultValue string) string
	// ReadInt64 读取一个int64类型配置值
	ReadInt64(key string, defaultValue int64) int64
	// ReadFloat64 读取一个float64类型配置值
	ReadFloat64(key string, defaultValue float64) float64
	// ReadBool 读取一个bool类型配置值
	ReadBool(key string, defaultValue bool) bool
	// WatchKey 监听配置变化
	WatchKey(key string) *ConfigWatch
}

// ConfigWatch 配置监听配置
type ConfigWatch struct {
	key         string
	use         bool
	callbackFun func(newValue interface{}, oldValue interface{})
}

func (a *ConfigWatch) setValue(newValue interface{}, oldValue interface{}) {
	if a.callbackFun != nil {
		a.callbackFun(newValue, oldValue)
	}
}

// SetInt64 设置监听int64值,是否忽略0
func (a *ConfigWatch) SetInt64(newValueSet *int64, ignoreZero bool) {
	a.use = true
	a.callbackFun = func(newValue interface{}, oldValue interface{}) {
		int64Value, e := conv.ToInt64E(newValue)
		if e == nil {
			if ignoreZero && int64Value == 0 {
				return
			}
			*newValueSet = int64Value
		}
	}
}

// SetInt64Callback 设置监听int64值执行回调
func (a *ConfigWatch) SetInt64Callback(fun func(newValue int64)) {
	if fun == nil {
		return
	}
	a.use = true
	a.callbackFun = func(newValue interface{}, oldValue interface{}) {
		int64Value, e := conv.ToInt64E(newValue)
		if e == nil {
			fun(int64Value)
		}
	}
}

// SetInt64CallbackWithOldView 设置监听int64值执行回调
func (a *ConfigWatch) SetInt64CallbackWithOldView(fun func(newValue int64, oldValue int64)) {
	if fun == nil {
		return
	}
	a.use = true
	a.callbackFun = func(newValue interface{}, oldValue interface{}) {
		int64Value, e := conv.ToInt64E(newValue)
		if e == nil {
			fun(int64Value, conv.ToInt64(oldValue))
		}
	}
}

// SetFloat64 设置监听float64值,是否忽略0
func (a *ConfigWatch) SetFloat64(newValueSet *float64, ignoreZero bool) {
	a.use = true
	a.callbackFun = func(newValue interface{}, oldValue interface{}) {
		float64Value, e := conv.ToFloat64E(newValue)
		if e == nil {
			if ignoreZero && float64Value == 0 {
				return
			}
			*newValueSet = float64Value
		}
	}
}

// SetFloat64Callback 设置监听float64值执行回调
func (a *ConfigWatch) SetFloat64Callback(fun func(newValue float64)) {
	if fun == nil {
		return
	}
	a.use = true
	a.callbackFun = func(newValue interface{}, oldValue interface{}) {
		float64Value, e := conv.ToFloat64E(newValue)
		if e == nil {
			fun(float64Value)
		}
	}
}

// SetFloat64CallbackWithOldView 设置监听float64值执行回调
func (a *ConfigWatch) SetFloat64CallbackWithOldView(fun func(newValue float64, oldValue float64)) {
	if fun == nil {
		return
	}
	a.use = true
	a.callbackFun = func(newValue interface{}, oldValue interface{}) {
		float64Value, e := conv.ToFloat64E(newValue)
		if e == nil {
			fun(float64Value, conv.ToFloat64(oldValue))
		}
	}
}

// SetString 设置监听string值,是否忽略空字符串
func (a *ConfigWatch) SetString(newValueSet *string, ignoreEmpty bool) {
	a.use = true
	a.callbackFun = func(newValue interface{}, oldValue interface{}) {
		str := common.ToString(newValue)
		str = strings.TrimSpace(str)
		if ignoreEmpty && str == "" {
			return
		}
		*newValueSet = str
	}
}

// SetStringCallback 设置监听int64值执行回调
func (a *ConfigWatch) SetStringCallback(fun func(newValue string), ignoreEmpty bool) {
	if fun == nil {
		return
	}
	a.use = true
	a.callbackFun = func(newValue interface{}, oldValue interface{}) {
		str := common.ToString(newValue)
		str = strings.TrimSpace(str)
		if ignoreEmpty && str == "" {
			return
		}
		fun(str)
	}
}

// SetStringCallbackWithOldView 设置监听int64值执行回调
func (a *ConfigWatch) SetStringCallbackWithOldView(fun func(newValue string, oldValue string), ignoreEmpty bool) {
	if fun == nil {
		return
	}
	a.use = true
	a.callbackFun = func(newValue interface{}, oldValue interface{}) {
		str := common.ToString(newValue)
		str = strings.TrimSpace(str)
		if ignoreEmpty && str == "" {
			return
		}
		fun(str, common.ToString(oldValue))
	}
}

var systemEnvStringTmpRegexp *regexp.Regexp

// 转换返回值中环境变量的内容
func systemParseEnvStringValue(val string) string {
	if systemEnvStringTmpRegexp == nil {
		systemEnvStringTmpRegexp, _ = regexp.Compile("\\$\\{.*?\\}")
	}
	if systemEnvStringTmpRegexp != nil {
		return systemEnvStringTmpRegexp.ReplaceAllStringFunc(val, func(s string) string {
			if len(s) < 4 {
				return s
			}
			index := s[2 : len(s)-1]
			return os.Getenv(index)
		})
	}
	return val
}

type Config struct {
	runMode        RunMode      //运行模式
	logLevel       logrus.Level //日志等级
	etcdHost       string       //etcd地址,默认: 127.0.0.1:2379
	traceServerURL string       //追踪服务地址
	logToFile      bool         //日志写入文件
	pprofPort      int          //pprof http端口号
	serverMode     ServerMode   //服务器模式
	broadcastPath  string       //广播地址
}

func (s *Config) TraceServerURL() string {
	return s.traceServerURL
}

func (s *Config) EtcdHosts() []string {
	if strings.TrimSpace(s.etcdHost) != "" {
		return strings.Split(s.etcdHost, ",")
	}
	return nil
}

func (s *Config) RpcBasePath() string {
	return s.runMode.String()
}

func (s *Config) PprofHttpPort() int {
	return s.pprofPort
}

func (s *Config) LogToFile() bool {
	return s.logToFile
}

func (s *Config) LogLevel() logrus.Level {
	return s.logLevel
}

func (s *Config) LoadFinishCallback() {
}

func (s *Config) RunMode() RunMode {
	return s.runMode
}

func (s *Config) ServerMode() ServerMode {
	return s.serverMode
}

func (s *Config) BroadcastPath() string {
	return s.broadcastPath
}

func (s *Config) Init(reader ConfigReader) {
	//运行模式
	s.initRunMode(reader)
	//etcd地址
	s.etcdHost = reader.ReadString(systemConfigEtcdHost, s.etcdHost)
	//追踪服务地址
	s.traceServerURL = reader.ReadString(systemConfigTraceServerURL, s.traceServerURL)
	if s.traceServerURL == "" {
		//zipkin地址
		s.traceServerURL = reader.ReadString(systemConfigZipkinURL, s.traceServerURL)
	}
	//日志写入文件
	s.logToFile = reader.ReadBool(systemConfigLogToFile, s.logToFile)
	s.pprofPort = int(reader.ReadInt64(pprofPortConfigKey, 0))
	s.broadcastPath = reader.ReadString(broadcastKey, s.broadcastPath)
}

// 获取服务器模式
func (s *Config) getServerMode() ServerMode {
	if s.runMode != PRO { //开发模式，返回的服务器都是开发环境
		return Develop
	}
	mode := strings.TrimSpace(os.Getenv("SERVER_MODE"))
	switch ServerMode(mode) {
	case Backup:
		return Backup
	case Develop:
		return Develop
	default:
		return Normal
	}
}

func (s *Config) initRunMode(reader ConfigReader) {
	runMode := reader.ReadString(systemConfigRunMode, "dev")
	switch RunMode(strings.ToLower(runMode)) {
	case DevTrace:
		s.runMode = DevTrace
		s.logLevel = logrus.TraceLevel
	case PRO:
		s.runMode = PRO
		s.logLevel = logrus.InfoLevel
	default:
		s.runMode = DEV
		s.logLevel = logrus.DebugLevel
	}
	//log.SetLogEnv(s.runMode.String())
	s.serverMode = s.getServerMode()
}

// 获取一个默认的公共配置
func getDefaultGloablConfig() *Config {
	return &Config{
		runMode:        DEV,
		logLevel:       logrus.DebugLevel,
		etcdHost:       "",
		traceServerURL: "",
		logToFile:      false,
		pprofPort:      0,
		serverMode:     Normal,
		broadcastPath:  "",
	}
}
